from django.contrib.auth import get_user_model, authenticate
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from django.contrib.auth.hashers import check_password
from rest_framework_simplejwt.tokens import RefreshToken
import logging
from django.conf import settings
from django.core.cache import cache
import random
import re
from alibabacloud_dysmsapi20170525.client import Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_dysmsapi20170525 import models as dysmsapi_models
import time

User = get_user_model()

# 获取日志记录器
logger = logging.getLogger('apps')

class LoginView(APIView):
    """用户登录视图"""
    permission_classes = [AllowAny]  # 允许未认证用户访问

    def post(self, request):
        """处理登录请求"""
        try:
            # 获取用户名和密码
            username = request.data.get('username')
            password = request.data.get('password')

            # 参数验证
            if not all([username, password]):
                return Response({
                    "code": 0,
                    "message": "用户名和密码不能为空"
                })

            # 验证用户名和密码
            user = authenticate(username=username, password=password)
            
            # 验证失败
            if not user:
                logger.warning(f"用户登录失败，用户名: {username}")
                return Response({
                    "code": 0,
                    "message": "用户名或密码错误"
                })

            # 验证成功，生成token
            refresh = RefreshToken.for_user(user)
            
            # 记录登录日志
            logger.info(f"用户登录成功，用户名: {username}")

            # 返回成功响应
            return Response({
                "code": 1,
                "message": "success",
                "data": {
                    "token": str(refresh.access_token),
                    "userId": user.id,
                    "username": user.username
                }
            })

        except Exception as e:
            logger.error(f"用户登录异常: {str(e)}")
            return Response({
                "code": 0,
                "message": f"登录失败: {str(e)}"
            })

class SendSmsCodeView(APIView):
    """发送短信验证码视图"""
    permission_classes = [AllowAny]  # 允许未认证用户访问

    def create_client(self):
        """
        创建阿里云客户端
        """
        config = open_api_models.Config(
            access_key_id=settings.ALIYUN_SMS['ACCESS_KEY_ID'],
            access_key_secret=settings.ALIYUN_SMS['ACCESS_KEY_SECRET'],
            endpoint=settings.ALIYUN_SMS['ENDPOINT']
        )
        return Client(config)

    def validate_mobile(self, mobile):
        """
        验证手机号格式
        """
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return False
        return True

    def check_send_interval(self, mobile):
        """
        检查发送间隔
        返回剩余等待时间（秒），如果可以发送则返回0
        """
        last_send_time = cache.get(f'sms_last_send_time:{mobile}')
        if last_send_time:
            now = int(time.time())
            elapsed = now - int(last_send_time)
            if elapsed < settings.SMS_CODE['INTERVAL_TIME']:
                return settings.SMS_CODE['INTERVAL_TIME'] - elapsed
        return 0

    def post(self, request):
        """处理发送短信验证码的请求"""
        try:
            # 获取手机号和类型(login或register)
            mobile = request.data.get('mobile')
            sms_type = request.data.get('sms_type', 'login')  # 默认为登录类型
            
            # 验证手机号格式
            if not mobile:
                return Response({
                    "code": 0,
                    "message": "手机号不能为空"
                })
            
            if not self.validate_mobile(mobile):
                return Response({
                    "code": 0,
                    "message": "手机号格式不正确"
                })

            # 根据验证码类型验证手机号
            is_registered = User.objects.filter(mobile=mobile).exists()
            if sms_type == 'login' and not is_registered:
                return Response({
                    "code": 0,
                    "message": "手机号未注册"
                })
            elif sms_type == 'register' and is_registered:
                return Response({
                    "code": 0,
                    "message": "手机号已注册"
                })

            # 检查发送间隔
            wait_time = self.check_send_interval(mobile)
            if wait_time > 0:
                return Response({
                    "code": 0,
                    "message": f"请{wait_time}秒后重试"
                })

            # 生成6位随机验证码
            code = ''.join(random.choices('0123456789', k=6))
            
            # 调用阿里云发送短信
            client = self.create_client()
            send_sms_request = dysmsapi_models.SendSmsRequest(
                phone_numbers=mobile,
                sign_name=settings.ALIYUN_SMS['SIGN_NAME'],
                template_code=settings.ALIYUN_SMS['TEMPLATE_CODE'],
                template_param='{"code":"%s"}' % code
            )
            
            # 发送短信
            response = client.send_sms(send_sms_request)
            
            if response.body.code == "OK":
                # 将验证码存入Redis
                cache.set(
                    f'sms_code:{mobile}',
                    code,
                    settings.SMS_CODE['EXPIRE_TIME']
                )
                # 记录发送时间
                cache.set(
                    f'sms_last_send_time:{mobile}',
                    int(time.time()),
                    settings.SMS_CODE['INTERVAL_TIME']
                )
                
                logger.info(f"短信验证码发送成功，手机号: {mobile}")
                return Response({
                    "code": 1,
                    "message": "success"
                })
            else:
                logger.error(f"短信发送失败，手机号: {mobile}, 错误信息: {response.body.message}")
                return Response({
                    "code": 0,
                    "message": "短信发送失败，请稍后重试"
                })

        except Exception as e:
            logger.error(f"发送短信验证码异常: {str(e)}")
            return Response({
                "code": 0,
                "message": "发送失败，请稍后重试"
            })

class RegisterView(APIView):
    """用户注册视图"""
    permission_classes = [AllowAny]

    def validate_mobile(self, mobile):
        """验证手机号格式"""
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return False
        return True

    def validate_password(self, password):
        """验证密码强度"""
        if len(password) < 6:
            return False, "密码长度不能小于6位"
        if len(password) > 20:
            return False, "密码长度不能大于20位"
        # 至少包含数字和字母
        if not re.search(r'[0-9]', password) or not re.search(r'[a-zA-Z]', password):
            return False, "密码必须包含数字和字母"
        return True, ""

    def post(self, request):
        """处理注册请求"""
        try:
            # 1. 获取参数
            mobile = request.data.get('mobile')
            code = request.data.get('code')
            password = request.data.get('password')
            password2 = request.data.get('password2')

            # 2. 参数完整性校验
            if not all([mobile, code, password, password2]):
                return Response({
                    "code": 0,
                    "message": "请填写完整的注册信息"
                })

            # 3. 手机号格式校验
            if not self.validate_mobile(mobile):
                return Response({
                    "code": 0,
                    "message": "手机号格式不正确"
                })

            # 4. 手机号是否已注册校验
            if User.objects.filter(mobile=mobile).exists():
                return Response({
                    "code": 0,
                    "message": "该手机号已注册"
                })

            # 5. 密码一致性校验
            if password != password2:
                return Response({
                    "code": 0,
                    "message": "两次密码不一致"
                })

            # 6. 密码强度校验
            is_valid, msg = self.validate_password(password)
            if not is_valid:
                return Response({
                    "code": 0,
                    "message": msg
                })

            # 7. 验证码校验
            redis_code = cache.get(f'sms_code:{mobile}')
            if not redis_code:
                return Response({
                    "code": 0,
                    "message": "验证码已过期"
                })

            if code != redis_code:
                return Response({
                    "code": 0,
                    "message": "验证码错误"
                })

            # 验证通过，清除验证码
            cache.delete(f'sms_code:{mobile}')

            # 8. 创建用户
            user = User.objects.create_user(
                username=mobile,  # 直接使用手机号作为用户名
                password=password,
                mobile=mobile
            )

            # 9. 生成JWT Token
            refresh = RefreshToken.for_user(user)

            # 记录注册日志
            logger.info(f"用户注册成功，手机号: {mobile}")

            # 10. 返回成功响应
            return Response({
                "code": 1,
                "message": "注册成功",
                "data": {
                    "token": str(refresh.access_token),
                    "userId": user.id,
                    "username": user.username
                }
            })

        except Exception as e:
            logger.error(f"用户注册异常: {str(e)}")
            return Response({
                "code": 0,
                "message": f"注册失败: {str(e)}"
            })

class MobileLoginView(APIView):
    """手机号登录视图"""
    permission_classes = [AllowAny]  # 允许未认证用户访问

    def validate_mobile(self, mobile):
        """验证手机号格式"""
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return False
        return True

    def post(self, request):
        """处理手机号登录请求"""
        try:
            # 1. 获取参数
            mobile = request.data.get('mobile')
            code = request.data.get('code')

            # 参数完整性校验
            if not all([mobile, code]):
                return Response({
                    "code": 0,
                    "message": "手机号和验证码不能为空"
                })

            # 2. 手机号格式校验
            if not self.validate_mobile(mobile):
                return Response({
                    "code": 0,
                    "message": "手机号格式不正确"
                })

            # 3. 手机号是否已注册校验
            try:
                user = User.objects.get(mobile=mobile)
            except User.DoesNotExist:
                logger.warning(f"未注册的手机号尝试登录: {mobile}")
                return Response({
                    "code": 0,
                    "message": "该手机号未注册"
                })

            # 4. 验证码校验
            redis_code = cache.get(f'sms_code:{mobile}')
            if not redis_code:
                return Response({
                    "code": 0,
                    "message": "验证码已过期"
                })

            if code != redis_code:
                return Response({
                    "code": 0,
                    "message": "验证码错误"
                })

            # 验证通过，清除验证码
            cache.delete(f'sms_code:{mobile}')

            # 5. 生成JWT Token
            refresh = RefreshToken.for_user(user)

            # 记录登录日志
            logger.info(f"用户手机号登录成功，手机号: {mobile}")

            # 6. 返回成功响应
            return Response({
                "code": 1,
                "message": "success",
                "data": {
                    "token": str(refresh.access_token),
                    "userId": user.id,
                    "username": user.username
                }
            })

        except Exception as e:
            logger.error(f"手机号登录异常: {str(e)}")
            return Response({
                "code": 0,
                "message": f"登录失败: {str(e)}"
            }) 